
import Banner from "./Banner";
import HealthAdvicePanel from "./HealthAdvicePanel";
import { UIManager } from "./UIManager";

const { ccclass, property } = cc._decorator;

/*** 所有 Bundle 包的名字，名字需要和包名保持一致 */
export enum Bundles {
    Sprits = "Sprits",
    AudioClips = "AudioClips",
    SharkSprite = "SharkSprite"
}

export enum RemoteBundles { }

@ccclass()
export class BundleManager extends cc.Component {
    @property(cc.Node)
    AgreePolicyPanel: cc.Node = null;
    private static _instance: any;
    public static get Instance(): BundleManager {
        if (BundleManager._instance == null) BundleManager._instance = new BundleManager();
        return BundleManager._instance;
    }

    /*** Key: Bundle 名字   Value: Bundle */
    static BundleMap: Map<string, cc.AssetManager.Bundle> = new Map<string, cc.AssetManager.Bundle>();

    static AgreePolicy: boolean = false;
    static LoadDone: boolean = false;

    start() {
        BundleManager.AgreePolicy = false;
        BundleManager.LoadDone = false;
        this.AgreePolicyPanel.getChildByName("ScrollView").getChildByName("view").getChildByName("content").getChildByName("PrivacyLabel").
            getComponent(cc.RichText).string = HealthAdvicePanel.PrivateText;
        UIManager.ShowTip("正在加载资源...");
        this.LoadBundles();
        if (cc.sys.localStorage.getItem("隐私同意") || Banner.Is_ANDROID) { //如果是安卓或者用户之前同意过不加载隐私协议
            BundleManager.AgreePolicy = true;
            this.SuccessCallback();
        } else {
            this.AgreePolicyPanel.active = true;
        }
    }

    Yes() {
        BundleManager.AgreePolicy = true;
        cc.sys.localStorage.setItem("隐私同意", "1");
        this.AgreePolicyPanel.active = false;
        this.SuccessCallback();
    }
    No() {
        UIManager.ShowTip("拒绝隐私协议无法进入游戏");
    }
    SuccessCallback() {
        if (BundleManager.AgreePolicy && BundleManager.LoadDone) {
            this.scheduleOnce(() => { cc.director.loadScene("MainPanel"); }, 2);
        }
    }

    LoadBundles() {
        const bundleNames = BundleManager.GetEnumValues(Bundles);
        const bundlePromises = bundleNames.map(name => {
            return new Promise((resolve, reject) => {
                cc.assetManager.loadBundle(name, (err, bundle) => {
                    if (err) {
                        reject([name, err]);
                    } else {
                        resolve(bundle);
                    }
                });
            });
        });

        Promise.all(bundlePromises)
            .then((bundles: cc.AssetManager.Bundle[]) => {
                for (let i = 0; i < bundles.length; i++) {
                    if (!BundleManager.BundleMap.has(bundles[i].name) || BundleManager.BundleMap.get(bundles[i].name) != bundles[i]) {
                        BundleManager.BundleMap.set(bundles[i].name, bundles[i]);
                        console.log(`加载本地 Bundle: ${bundles[i].name} 成功`);
                    }
                }
                UIManager.ShowTip("加载资源成功");

                BundleManager.LoadDone = true;
                this.SuccessCallback();
            })
            .catch(error => {
                UIManager.ShowTip("加载资源失败");
                console.error(`加载本地 Bundle:${error[0]} 失败:[${error[1]}]`);
            });
    }

    //加载远程包无论成功失败都进入游戏
    LoadRemoteBundles(callback: Function = null) {
        const bundleNames = BundleManager.GetEnumValues(RemoteBundles);
        const bundlePromises = bundleNames.map(name => {
            return new Promise((resolve, reject) => {
                cc.assetManager.loadBundle(name, (err, bundle) => {
                    if (err) {
                        reject([name, err]);
                    } else {
                        resolve(bundle);
                    }
                });
            });
        });

        Promise.all(bundlePromises)
            .then((bundles: cc.AssetManager.Bundle[]) => {
                for (let i = 0; i < bundles.length; i++) {
                    if (!BundleManager.BundleMap.has(bundles[i].name) || BundleManager.BundleMap.get(bundles[i].name) != bundles[i]) {
                        BundleManager.BundleMap.set(bundles[i].name, bundles[i]);
                        console.log(`加载远程 Bundle: ${bundles[i].name} 成功`);
                    }
                }
                callback && callback();
            })
            .catch(error => {
                callback && callback();
                UIManager.ShowTip("加载资源失败...");

                console.error(`加载远程 Bundle:${error[0]} 失败:[${error[1]}]`);
            });
    }

    /*** 设置 Bundle 包 */
    public static SetBundle(name: string, cb: Function = null) {
        cc.assetManager.loadBundle(name, (err, bundle) => {
            if (err) {
                console.error(`加载 Bundle 包：${name} 失败。`);
                return;
            }
            BundleManager.BundleMap.set(name, bundle);
            cb && cb();
        });
    }

    /*** 获取 Bundle 包 */
    public static GetBundle(bundle: string) {
        if (this.CheckBundleIsNull(bundle)) return;
        return this.BundleMap.get(bundle);
    }

    /*** 加载 Bundle 包内资源 */
    public static Load(bundle: string, path: string, type: any, cb: Function = () => { }) {
        if (this.CheckBundleIsNull(bundle)) return;
        this.BundleMap.get(bundle).load(path, type, (err: any, res: any) => {
            if (err) {
                console.error(err.message || err);
                cb(err, res);
                return;
            }

            cb && cb(null, res);
        })
    }

    /*** 加载 Bundle 包内场景 */
    public static LoadBundleScene(bundle: string, scene: string) {
        if (this.CheckBundleIsNull(bundle)) return;
        this.BundleMap.get(bundle).loadScene(scene, cc.Scene, (err, scene) => {
            if (err) {
                console.error(`加载 Bundle: ${bundle} 场景失败: ${scene}`);
                return;
            }

            cc.director.runScene(scene);
        });
    }

    /*** 加载 Bundle 包内预制体 */
    public static LoadPrefab(bundle: string, path: string) {
        if (this.CheckBundleIsNull(bundle)) return;
        return new Promise((resolve, reject) => {
            this.Load(bundle, `${path}`, cc.Prefab, (err: any, prefab: cc.Prefab) => {
                if (err) {
                    console.error(`加载 Bundle: ${bundle} cc.Prefab 加载失败 Path: ${path}`);
                    reject && reject();
                    return;
                }

                resolve && resolve(prefab);
            });
        });
    }

    /*** 加载 Bundle 包内 cc.SpriteFrame */
    public static LoadSpriteFrame(bundle: string, path: string) {
        if (this.CheckBundleIsNull(bundle)) return;
        return new Promise((resolve, reject) => {
            this.Load(bundle, `${path}`, cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
                if (err) {
                    console.error(`加载 Bundle: ${bundle} cc.SpriteFrame 加载失败 Path: ${path}`);
                    reject && reject();
                    return;
                }

                resolve && resolve(spriteFrame);
            });
        });
    }

    /*** 加载 Bundle 包内 cc.Texture2D */
    public static LoadTexture(bundle: string, path: string) {
        if (this.CheckBundleIsNull(bundle)) return;
        return new Promise((resolve, reject) => {
            this.Load(bundle, `${path}`, cc.Texture2D, (err: any, texture: cc.Texture2D) => {
                if (err) {
                    console.error(`加载 Bundle: ${bundle} cc.Texture2D 加载失败 Path: ${path}`);
                    reject && reject();
                    return;
                }

                resolve && resolve(texture);
            });
        });
    }

    /*** 检查 Bunle 包是否为空，可以特殊处理，请求用户连接网络重启游戏 */
    private static CheckBundleIsNull(bundle: string): boolean {
        if (!this.BundleMap.has(bundle)) {
            console.error(`不存在此 Bundle: ${bundle}，请检查 Bundle 名称或者网络`);
            return true;
        }
        return false;
    }

    public static GetEnumValues(enumType: any): string[] {
        const enumValues = Object.keys(enumType)
            .map(key => enumType[key])
            .filter(value => typeof value === 'string');

        return enumValues as string[];
    }
}